/*
 * Copyright 2013 Pavel Stastny <pavel.stastny at gmail.com>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.aplikator.client.local.wizards;

import com.github.gwtbootstrap.client.ui.Button;
import com.github.gwtbootstrap.client.ui.FluidContainer;
import com.github.gwtbootstrap.client.ui.Modal;
import com.github.gwtbootstrap.client.ui.ModalFooter;
import com.google.gwt.dom.client.Style;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.*;
import org.aplikator.client.local.Aplikator;
import org.aplikator.client.local.widgets.HasFields;
import org.aplikator.client.local.widgets.WizardFormWidget;
import org.aplikator.client.shared.data.ClientContext;
import org.aplikator.client.shared.data.Record;
import org.aplikator.client.shared.descriptor.FunctionDTO;
import org.aplikator.client.shared.descriptor.WizardPageDTO;
import org.aplikator.client.shared.rpc.ParameterWrapperRunFunction;
import org.jboss.errai.common.client.api.RemoteCallback;

/**
 * Wizard support
 * @author Pavel Stastny <pavel.stastny at gmail.com>
 */
public class WizardSupport {
    
    
    
    /** Function DTO  object */
    private FunctionDTO function;

    /** Dialog box  */
    private DialogBox dialogBox;
    /** Deckpanel */
    private DeckPanel deckPanel;        

    /** Buttons */
    private Button okButton;
    private Button cancelButton;
    private Button nextButton;
    private Button prevButton;
    
    /** Current form widget */
    private WizardFormWidget currentWidget;
    /** Current pageDTO */
    private WizardPageDTO currentPageDTO;

    /** Client properties record */
    private Record clientPropertiesRecord;
    
    /** Flag - true if the window is intialized */
    private boolean windowInitialized = false;

    /** Containers */
    private FluidContainer currentContainer;
    private DockLayoutPanel dialogContents;

    //private Record originalRecord;
    private HasFields ownerFields;
    
    private WizardSupportCallbacks callbacks;
    
    public WizardSupport(final FunctionDTO function, final HasFields ownerFields, final WizardSupportCallbacks callbacks) {
        this.function = function;
        this.ownerFields = ownerFields;
        this.callbacks = callbacks;
    }

    public Record getOriginalFormRecord() {
    	return this.ownerFields != null ? this.ownerFields.getOriginal() : null;
    }
    
    
    /** Collecting record */
    private void collectRecord() {
        if (this.clientPropertiesRecord != null && this.currentWidget != null ) {
            this.clientPropertiesRecord = this.currentWidget.addFieldsToExistingRecord(this.clientPropertiesRecord);
        } else {
            this.clientPropertiesRecord = new Record();
        }
    }

    /** Request for change page */
    public void changePageRequest(final boolean forw) {
        this.collectRecord();

        ClientContext clientContext = Aplikator.clientContext.clone();
        clientContext.setCurrentRecord(getOriginalFormRecord());
        ParameterWrapperRunFunction param = new ParameterWrapperRunFunction(
                this.function, 
                clientContext, 
                this.clientPropertiesRecord);

        Aplikator.aplikatorService.call(new RemoteCallback<WizardPageDTO>() {
            @Override
            public void callback(WizardPageDTO response) {
            	WizardSupport.this.callbacks.wizardPageCallback(response, forw);
            	if (response != null) {
                    if (windowInitialized) {
                        onReceiveNewPageDTO(response);
                    } else {
                        initializeDialog(response);
                    }
                } else { 
                	runFunction();
                }
            }
        }).getWizardPage(function.getId(), this.currentPageDTO != null ? this.currentPageDTO.getPageId() : null, forw , param);
    }


    
    
    /**
     * On received page
     * @param pageDTO 
     */
    private void onReceiveNewPageDTO(WizardPageDTO pageDTO) {
        this.currentPageDTO = pageDTO;
        this.currentContainer = new FluidContainer();
        this.currentWidget = new WizardFormWidget(pageDTO, pageDTO.getFormDescriptor());

        if (pageDTO.getClientRecord() != null) {
            this.clientPropertiesRecord = pageDTO.getClientRecord();
            this.currentWidget.setOriginal(this.clientPropertiesRecord);
            this.currentWidget.populateFormWithSimpleData(true);
        }
        
        this.currentContainer.add(this.currentWidget);
        this.currentContainer.setWidth("90%");
        this.deckPanel.add(this.currentContainer);
        this.deckPanel.showWidget(this.deckPanel.getVisibleWidget()+1);
        if (this.deckPanel.getWidgetCount() > 1) {
            this.deckPanel.remove(0);
        }
        this.onPageChanged();
    }

    private void onPageChanged() {
        if (this.currentPageDTO != null) {
            this.okButton.setEnabled(this.currentPageDTO.isHasExecute());
            this.nextButton.setEnabled(this.currentPageDTO.isHasNext());
            this.prevButton.setEnabled(this.currentPageDTO.isHasPrevious());
        }
    }

    /**
     * Dialog initialization
     * @param pageDTO 
     */
    private void initializeDialog(WizardPageDTO pageDTO) {
        WizardFormWidget form = new WizardFormWidget(pageDTO, pageDTO.getFormDescriptor());

        this.deckPanel = new DeckPanel();
        this.dialogContents = new DockLayoutPanel(Style.Unit.PCT);
        this.dialogBox  = new DialogBox();
        
        
        this.dialogContents.setSize("648px", "484px");
        this.dialogBox.setWidget(this.dialogContents);
        this.dialogContents.addSouth(buttonsPane(this.deckPanel, this.dialogBox), 15);

        this.dialogContents.add(this.deckPanel);
        
        this.onReceiveNewPageDTO(pageDTO);
        
        this.dialogBox.setText("Parametry pro funkci "+function.getLocalizedName());

        this.dialogBox.setAnimationEnabled(true);
        this.dialogBox.setModal(true);
        this.dialogBox.center();
        
        this.windowInitialized = true;
    }

    public void runFunction() {
        ClientContext clientContext = Aplikator.clientContext.clone();
        clientContext.setCurrentRecord(getOriginalFormRecord());
        this.callbacks.runBeforeFunctionCallback();
        
        Aplikator.aplikatorService.call( new RemoteCallback<String>() {

                public void callback(String response) {
                WizardSupport.this.callbacks.runAfterFunctionCallback();

                final Modal informBox  = new Modal();
                informBox.setTitle(" Vysledek funkce ");
                Label label = new Label();
                label.setWordWrap(true);

                label.setText(response);
                informBox.add(label);

                ModalFooter buttonPanel = new ModalFooter();
                Button OKButton = new Button("OK", new ClickHandler() {
                    public void onClick(ClickEvent event) {
                        informBox.hide();
                    }
                });
                buttonPanel.add(OKButton);
                informBox.add(buttonPanel);

                informBox.show();
                
                
                
             }
        }).runFunction(new ParameterWrapperRunFunction(this.function, clientContext, this.clientPropertiesRecord));
    }

    private Grid buttonsPane(final DeckPanel deckPanel, final DialogBox dialogBox) {
        this.okButton = createOKButton(dialogBox);
        this.cancelButton = createCancelButton(dialogBox);
        this.nextButton = createNextButton(dialogBox);
        this.prevButton = createPrevButton(dialogBox);
        Grid grid = new Grid(1, 5);
        grid.setWidget(0, 0, new SimplePanel());
        grid.getCellFormatter().setWidth(0, 0, "75%");
        grid.setWidget(0, 4, this.okButton);
        grid.setWidget(0, 3, this.cancelButton);
        grid.setWidget(0, 2, this.nextButton);
        grid.setWidget(0, 1, this.prevButton);
        return grid;
    }

    private void hideDialog() {
        this.dialogBox.hide();
    
        this.dialogBox = null;
        this.deckPanel = null;        
        this.okButton = null;
        this.cancelButton = null;
        this.nextButton = null;
        this.prevButton = null;
    
        this.currentWidget = null;
        this.currentPageDTO = null;

        this.clientPropertiesRecord = null;
        this.windowInitialized = false;
    
    }
    
    private Button createOKButton(final DialogBox dialogBox) {
        Button okButton = new Button("Ok", new ClickHandler() {
            public void onClick(ClickEvent event) {
                collectRecord();
                runFunction();
                hideDialog();
            }
        });
        return okButton;
    }

    private Button createCancelButton(final DialogBox dialogBox) {
        Button closeButton = new Button("Cancel", new ClickHandler() {
            public void onClick(ClickEvent event) {
                hideDialog();
            }
        });
        return closeButton;
    }

    private Button createPrevButton(final DialogBox dialogBox) {
        Button prevButton = new Button("<<", new ClickHandler() {
            public void onClick(ClickEvent event) {
                changePageRequest(false);
            }
        });
        return prevButton;
    }

    private Button createNextButton(final DialogBox dialogBox) {
        Button nextButton = new Button(">>", new ClickHandler() {
            public void onClick(ClickEvent event) {
                changePageRequest(true);
            }
        });
        return nextButton;
    }
}
